package tag

import (
	"context"

	"BookStack/pkg/errors"
)

// Service 标签领域服务接口
type Service interface {
	// CreateTag 创建标签
	CreateTag(ctx context.Context, name, slug, description string, tagType int) (*Tag, error)

	// UpdateTag 更新标签
	UpdateTag(ctx context.Context, id uint, name, slug, description string, tagType int) (*Tag, error)

	// DeleteTag 删除标签
	DeleteTag(ctx context.Context, id uint) error

	// BatchDeleteTags 批量删除标签
	BatchDeleteTags(ctx context.Context, ids []uint) error

	// GetTag 获取标签
	GetTag(ctx context.Context, id uint) (*Tag, error)

	// GetTagBySlug 根据Slug获取标签
	GetTagBySlug(ctx context.Context, slug string) (*Tag, error)

	// GetTagByName 根据Name获取标签
	GetTagByName(ctx context.Context, name string) (*Tag, error)

	// ExistsByName 检查名称是否存在
	ExistsByName(ctx context.Context, name string, tagType int, excludeID uint) (bool, error)

	// ExistsBySlug 检查Slug是否存在
	ExistsBySlug(ctx context.Context, slug string, tagType int, excludeID uint) (bool, error)

	// ListTags 获取标签列表
	ListTags(ctx context.Context, params *ListParams) ([]*Tag, int64, error)

	// GetHotTags 获取热门标签
	GetHotTags(ctx context.Context, tagType *int, limit int) ([]*Tag, error)

	// GetTagStat 获取标签使用统计
	GetTagStat(ctx context.Context, id uint) (articleCount int64, bookCount int64, err error)
}

// service 标签领域服务实现
type service struct {
	repo Repository
}

// NewService 创建标签领域服务
func NewService(repo Repository) Service {
	return &service{
		repo: repo,
	}
}

// CreateTag 创建标签
func (s *service) CreateTag(ctx context.Context, name, slug, description string, tagType int) (*Tag, error) {
	// 验证标签类型
	if !IsValidType(tagType) {
		return nil, errors.New(errors.ErrCodeTagTypeInvalid, "")
	}

	// 检查名称是否已存在
	exists, err := s.repo.ExistsByName(ctx, name, tagType, 0)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeTagNameExists, "")
	}

	// 检查Slug是否已存在
	exists, err = s.repo.ExistsBySlug(ctx, slug, tagType, 0)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if exists {
		return nil, errors.New(errors.ErrCodeTagSlugExists, "")
	}

	// 创建标签
	tag := NewTag(name, slug, description, tagType)
	if err := s.repo.Create(ctx, tag); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return tag, nil
}

// UpdateTag 更新标签
func (s *service) UpdateTag(ctx context.Context, id uint, name, slug, description string, tagType int) (*Tag, error) {
	// 验证标签类型
	if !IsValidType(tagType) {
		return nil, errors.New(errors.ErrCodeTagTypeInvalid, "")
	}

	// 获取标签
	tag, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, err
	}
	if tag == nil {
		return nil, errors.New(errors.ErrCodeTagNotFound, "")
	}

	// 检查名称是否已存在
	if name != tag.Name {
		exists, err := s.repo.ExistsByName(ctx, name, tagType, id)
		if err != nil {
			return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
		}
		if exists {
			return nil, errors.New(errors.ErrCodeTagNameExists, "")
		}
	}

	// 检查Slug是否已存在
	if slug != tag.Slug {
		exists, err := s.repo.ExistsBySlug(ctx, slug, tagType, id)
		if err != nil {
			return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
		}
		if exists {
			return nil, errors.New(errors.ErrCodeTagSlugExists, "")
		}
	}

	// 更新标签
	tag.Name = name
	tag.Slug = slug
	tag.Description = description
	tag.Type = tagType

	if err := s.repo.Update(ctx, tag); err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return tag, nil
}

// DeleteTag 删除标签
func (s *service) DeleteTag(ctx context.Context, id uint) error {
	// 获取标签
	tag, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return err
	}
	if tag == nil {
		return errors.New(errors.ErrCodeTagNotFound, "")
	}

	// 检查标签是否被使用
	if tag.UsageCount > 0 {
		return errors.New(errors.ErrCodeTagUsed, "")
	}

	// 删除标签
	if err := s.repo.Delete(ctx, id); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// BatchDeleteTags 批量删除标签
func (s *service) BatchDeleteTags(ctx context.Context, ids []uint) error {
	// 检查每个标签是否存在和是否被使用
	for _, id := range ids {
		tag, err := s.repo.GetByID(ctx, id)
		if err != nil {
			return err
		}
		if tag == nil {
			return errors.New(errors.ErrCodeTagNotFound, "").WithDetails(map[string]interface{}{
				"id": id,
			})
		}
		if tag.UsageCount > 0 {
			return errors.New(errors.ErrCodeTagUsed, "").WithDetails(map[string]interface{}{
				"id":   id,
				"name": tag.Name,
			})
		}
	}

	// 批量删除标签
	if err := s.repo.BatchDelete(ctx, ids); err != nil {
		return errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return nil
}

// GetTag 获取标签
func (s *service) GetTag(ctx context.Context, id uint) (*Tag, error) {
	tag, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if tag == nil {
		return nil, errors.New(errors.ErrCodeTagNotFound, "")
	}
	return tag, nil
}

// GetTagBySlug 根据Slug获取标签
func (s *service) GetTagBySlug(ctx context.Context, slug string) (*Tag, error) {
	tag, err := s.repo.GetBySlug(ctx, slug)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if tag == nil {
		return nil, errors.New(errors.ErrCodeTagNotFound, "")
	}
	return tag, nil
}

// GetTagByName 根据Name获取标签
func (s *service) GetTagByName(ctx context.Context, name string) (*Tag, error) {
	tag, err := s.repo.GetByName(ctx, name)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if tag == nil {
		return nil, errors.New(errors.ErrCodeTagNotFound, "")
	}
	return tag, nil
}

// ListTags 获取标签列表
func (s *service) ListTags(ctx context.Context, params *ListParams) ([]*Tag, int64, error) {
	// 获取标签列表
	tags, total, err := s.repo.List(ctx, params)
	if err != nil {
		return nil, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return tags, total, nil
}

// GetHotTags 获取热门标签
func (s *service) GetHotTags(ctx context.Context, tagType *int, limit int) ([]*Tag, error) {
	if limit <= 0 {
		limit = 10 // 默认返回10个热门标签
	}
	if limit > 100 {
		limit = 100 // 最多返回100个
	}

	tags, err := s.repo.GetHotTags(ctx, tagType, limit)
	if err != nil {
		return nil, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return tags, nil
}

// GetTagStat 获取标签使用统计
func (s *service) GetTagStat(ctx context.Context, id uint) (articleCount int64, bookCount int64, err error) {
	// 获取标签
	tag, err := s.repo.GetByID(ctx, id)
	if err != nil {
		return 0, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	if tag == nil {
		return 0, 0, errors.New(errors.ErrCodeTagNotFound, "")
	}

	// 获取统计数据
	articleCount, bookCount, err = s.repo.GetTagStat(ctx, id)
	if err != nil {
		return 0, 0, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}

	return articleCount, bookCount, nil
}

// ExistsByName 检查名称是否存在
func (s *service) ExistsByName(ctx context.Context, name string, tagType int, excludeID uint) (bool, error) {
	exists, err := s.repo.ExistsByName(ctx, name, tagType, excludeID)
	if err != nil {
		return false, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return exists, nil
}

// ExistsBySlug 检查Slug是否存在
func (s *service) ExistsBySlug(ctx context.Context, slug string, tagType int, excludeID uint) (bool, error) {
	exists, err := s.repo.ExistsBySlug(ctx, slug, tagType, excludeID)
	if err != nil {
		return false, errors.Wrap(err, errors.ErrCodeDatabase, "")
	}
	return exists, nil
}
